package com.jt.aop;

import com.jt.anno.CacheFind;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.ShardedJedis;

import java.util.Arrays;

@Component  //讲对象交给spring容器管理
@Aspect     //表示我是一个切面
public class CacheAOP {
    @Autowired
//    private Jedis jedis;
//    private ShardedJedis jedis;
    private JedisCluster jedis;
    /**
     *  练习joinPiont
     *
     */
    @Before("@annotation(com.jt.anno.CacheFind)")
    public void before(JoinPoint joinPoint){
        Object target = joinPoint.getTarget();//获取目标对象
        Object[] args = joinPoint.getArgs();//获取方法参数的
        String targetName = joinPoint.getSignature().getDeclaringTypeName();//获取目标对象名称
        Class targetClass = joinPoint.getSignature().getDeclaringType();//获取目标对象的类型
        String methodName = joinPoint.getSignature().getName();//获取目标方法的名称
        System.out.println(target);
        System.out.println(args);
        System.out.println(targetName);
        System.out.println(targetClass);
        System.out.println(methodName);
    }



    /**
     * 拦截@CacheFin注解标识的方法
     * 同志选择：缓存的实现应该选择环绕通知
     */
    @Around("@annotation(cacheFind)")
    public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){

        //1.如何获取用户在注解中填写的内容呢???  如何获取注解对象....
        String key = cacheFind.key();   //前缀  ITEM_CAT_PARENTID
        //2.如何获取目标对象的参数呢???
        Object[] array = joinPoint.getArgs();
        key += "::"+Arrays.toString(array); // "ITEM_CAT_PARENTID::[0]"

        //3.从redis中获取数据
        Object result = null;
        if(jedis.exists(key)){
            //需要获取json数据之后,直接转化为对象返回!!
            String json = jedis.get(key);
            //如何获取返回值类型
            MethodSignature methodSignature =
                    (MethodSignature) joinPoint.getSignature();
            Class targetClass = methodSignature.getReturnType();
            result = ObjectMapperUtil.toObject(json,targetClass);
            System.out.println("AOP实现缓存的查询!!!");
        }else{
            //key不存在,应该查询数据库
            try {
                result = joinPoint.proceed();    //执行目标方法,获取返回值结果
                String json = ObjectMapperUtil.toJson(result);
                if(cacheFind.seconds()>0){       //判断是否需要超时时间
                    jedis.setex(key, cacheFind.seconds(), json);
                }else{
                    jedis.set(key,json);
                }
                System.out.println("AOP执行数据库操作!!!");
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                throw new RuntimeException(throwable);
            }
        }
        return result;
    }






    /**
     * aop=切入点表达式+通知方法
     *
     * 拦截需求
     * 1.要求拦截itemCatServiceImpl的bean
     * 2.拦截com.jt.service下的所有类
     * 3.拦截com.jt.service下的所有类及方法
     *
     */
//    @Pointcut(value = "bean(itemCatServiceImpl)")
//    @Pointcut(value = "within(com.jt.service..*")
    //拦截com.jt.service下的所有类的所有方法的任一参数类型
//    @Pointcut(value = "execution(* com.jt.service..*.*(..))")
//    @Pointcut("execution(int com.jt.service..*.add*(String))")
//    @Pointcut("@annotation()")
//    public void pointcut(){
//
//    }
//
//    //定义前置通知
//    @Before("pointcut()")
//    public void before(){
//        System.out.println("我是前置通知");
//    }
//
}
